home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / ODF Release 3 / ODFDev / Bitmap / Sources / odfjpeg.cpp < prev    next >
Encoding:
Text File  |  1996-12-16  |  9.6 KB  |  316 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                odfjpeg.cpp
  4. //    Release Version:    $ ODF 3 $
  5. //
  6. //    Author:                Mark Lanett
  7. //
  8. //    Copyright:    (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9. //
  10. //========================================================================================
  11. //
  12. //    Reads a JPEG using the Independent JPEG Group's free JPEG library.
  13. //    Returns an FW_CBitmap.
  14. //    Note: the returned bitmap is 16-bit and is not dithered.
  15. //    
  16. //    6/3/96 mlanett Checked in. Derived from example.c from the JPEG library.
  17. //    
  18.  
  19. #include "FWOS.hpp"
  20. #include "odfjpeg.h"
  21.  
  22. #ifndef FWMEMMGR_H
  23. #include "FWMemMgr.h"
  24. #endif
  25.  
  26. #ifndef FWRECSHP_H
  27. #include "FWRecShp.h"
  28. #endif
  29.  
  30. // Why does everyone insist on defining boolean themselves?
  31. // Something wrong with "char" or "int" or "ijg_boolean"?
  32.  
  33. #define boolean yet_another_conflicting_boolean_type
  34.  
  35. extern "C" {
  36. #include "jinclude.h"
  37. #include "jpeglib.h"
  38. #include "jerror.h"
  39. }
  40.  
  41. #include <setjmp.h>
  42. #include "SLASinks.xh"
  43.  
  44. #pragma segment odfjpeg
  45.  
  46. /*-----------------------------------------------------------------------------
  47.     Prototypes
  48.     
  49. -----------------------------------------------------------------------------*/
  50.  
  51. extern "C" {
  52. void ODF_JPEG_DecodeRow (JOCTET* samples, int inbytes, Ptr base, int outbytes);
  53.  
  54.     // The following prototypes are necessary for compilers that treat pointers
  55.     // to static methods of a class as different from extern "C" functions. [sfu]
  56.     
  57.     typedef void (*t_jpegemPtr)(j_common_ptr cinfo);
  58.     typedef void (*t_jpegcm1Ptr)(jpeg_decompress_struct *);
  59.     typedef int (*t_jpegcm2Ptr)(jpeg_decompress_struct *);
  60.     typedef void (*t_jpegcm3Ptr)(jpeg_decompress_struct *, long);
  61. }
  62.  
  63. /*-----------------------------------------------------------------------------
  64.     Utilities
  65. -----------------------------------------------------------------------------*/
  66.  
  67. class TempMacLockedPixels {
  68. public:
  69.     FW_DECLARE_AUTO (TempMacLockedPixels)
  70.                     TempMacLockedPixels (PixMapHandle lockedPixMap);
  71.                     ~TempMacLockedPixels ();
  72. private:
  73.     PixMapHandle     fPixMap;
  74. };
  75.  
  76. FW_DEFINE_AUTO (TempMacLockedPixels)
  77.  
  78. TempMacLockedPixels::TempMacLockedPixels (PixMapHandle lockedPixMap)
  79. :    fPixMap (lockedPixMap)
  80. {
  81.     FW_END_CONSTRUCTOR
  82. }
  83.  
  84. TempMacLockedPixels::~TempMacLockedPixels ()
  85. {
  86.     FW_START_DESTRUCTOR
  87.     
  88.     ::UnlockPixels (fPixMap);
  89. }
  90.  
  91. /*-----------------------------------------------------------------------------
  92.     ODF_JPEG_ErrorManager
  93. -----------------------------------------------------------------------------*/
  94.  
  95. struct ODF_JPEG_ErrorManager: public jpeg_error_mgr {
  96.     jmp_buf         fExitBuffer;
  97.     static void     ErrorExit (j_common_ptr cinfo);
  98. };
  99.  
  100. void ODF_JPEG_ErrorManager::ErrorExit (j_common_ptr cinfo)
  101. {
  102.     ODF_JPEG_ErrorManager* self = (ODF_JPEG_ErrorManager*) cinfo->err;
  103.     // (cinfo->err->output_message) (cinfo);
  104.     longjmp (self->fExitBuffer, 1);
  105. }
  106.  
  107. /*-----------------------------------------------------------------------------
  108.     ODF_JPEG_SourceManager
  109. -----------------------------------------------------------------------------*/
  110.  
  111. struct ODF_JPEG_SourceManager: public jpeg_source_mgr {
  112.                     FW_DECLARE_AUTO(ODF_JPEG_SourceManager)
  113.                     ODF_JPEG_SourceManager     (Environment* ev, FW_OSink* sink, size_t bufferSize = 1000);
  114.                     ~ODF_JPEG_SourceManager ();
  115.                     
  116.     static void     InitSource            (j_decompress_ptr cinfo);
  117.     static boolean     FillInputBuffer        (j_decompress_ptr cinfo);
  118.     static void     SkipInputData        (j_decompress_ptr cinfo, long num_bytes);
  119.     static void     TermSource            (j_decompress_ptr cinfo);
  120. private:
  121.     Environment*     fEv;
  122.     FW_OSink*         fSink;
  123.     size_t             fBufferSize;
  124.     JOCTET*         fBuffer;
  125.     FW_Boolean         fStartOfFile;
  126. };
  127.  
  128. FW_DEFINE_AUTO(ODF_JPEG_SourceManager)
  129.  
  130. ODF_JPEG_SourceManager::ODF_JPEG_SourceManager (Environment* ev, FW_OSink* sink, size_t bufferSize)
  131. :    fEv (ev)
  132. ,    fSink (sink)
  133. ,    fBufferSize (bufferSize)
  134. {
  135.     fBuffer = (JOCTET*) FW_CMemoryManager::AllocateBlock (fBufferSize);
  136.     FW_END_CONSTRUCTOR
  137. }
  138.  
  139. ODF_JPEG_SourceManager::~ODF_JPEG_SourceManager ()
  140. {
  141.     FW_START_DESTRUCTOR
  142.     FW_CMemoryManager::FreeBlock (fBuffer);
  143. }
  144.  
  145. void ODF_JPEG_SourceManager::InitSource (j_decompress_ptr cinfo)
  146. {
  147.     ODF_JPEG_SourceManager* self = (ODF_JPEG_SourceManager*) cinfo->src;
  148.     self->fStartOfFile = true;
  149. }
  150.  
  151. boolean ODF_JPEG_SourceManager::FillInputBuffer (j_decompress_ptr cinfo)
  152. {
  153.     ODF_JPEG_SourceManager* self = (ODF_JPEG_SourceManager*) cinfo->src;
  154.     
  155.     size_t available = self->fSink->GetReadableBytes (self->fEv);
  156.     if (available == 0) {
  157.         // Is it an empty data set?
  158.         if (self->fStartOfFile)
  159.             ERREXIT (cinfo, JERR_INPUT_EMPTY);
  160.         // If it's just a truncated dataset, terminate it (and return a warning?)
  161.         WARNMS (cinfo, JWRN_JPEG_EOF);
  162.         self->fBuffer[0] = 0xFF;
  163.         self->fBuffer[1] = JPEG_EOI;
  164.         available = 2;
  165.     }
  166.     else {
  167.         if (self->fBufferSize < available)
  168.             available = self->fBufferSize;
  169.         self->fSink->Read (self->fEv, self->fBuffer, available);
  170.     }
  171.     
  172.     self->next_input_byte = self->fBuffer;
  173.     self->bytes_in_buffer = available;
  174.     self->fStartOfFile = false;
  175.     
  176.     return true;
  177. }
  178.  
  179. void ODF_JPEG_SourceManager::SkipInputData (j_decompress_ptr cinfo, long num_bytes)
  180. {
  181.     ODF_JPEG_SourceManager* self = (ODF_JPEG_SourceManager*) cinfo->src;
  182.     
  183.     while (self->bytes_in_buffer < num_bytes) {
  184.         num_bytes -= self->bytes_in_buffer;
  185.         FillInputBuffer (cinfo);
  186.     }
  187.     
  188.     self->next_input_byte += num_bytes;
  189.     self->bytes_in_buffer -= num_bytes;
  190. }
  191.  
  192. void ODF_JPEG_SourceManager::TermSource (j_decompress_ptr cinfo)
  193. {
  194. FW_UNUSED(cinfo);
  195. }
  196.  
  197. /*-----------------------------------------------------------------------------
  198.     ODF_JPEG_DecodeRow
  199. -----------------------------------------------------------------------------*/
  200.  
  201. void ODF_JPEG_DecodeRow (JOCTET* samples, int inbytes, Ptr base, int outbytes)
  202. {
  203. /*
  204.     Now that we have a row of samples, rewrite them into a 16-bit Mac pixmap.
  205. */
  206.     while (3 <= inbytes && 2 <= outbytes)  {
  207.         // Input from samples
  208.         JOCTET red = *samples++;
  209.         JOCTET green = *samples++;
  210.         JOCTET blue = *samples++;
  211.         inbytes -= 3;
  212.         // Output to pixmap
  213.         unsigned short rgb16 = ((red >> 3) << 10) | ((green >> 3) << 5) | (blue >> 3);
  214.         *((unsigned short*)base) = rgb16;
  215.         base += 2;
  216.         outbytes -= 2;
  217.     }
  218. }
  219.  
  220. /*-----------------------------------------------------------------------------
  221.     ODF_JPEG_Read
  222. -----------------------------------------------------------------------------*/
  223.  
  224. FW_CBitmap ODF_JPEG_Read (Environment* ev, FW_OSink* sink)
  225. {
  226.     jpeg_decompress_struct cinfo;
  227.     ODF_JPEG_ErrorManager     jerr;
  228.     ODF_JPEG_SourceManager     src (ev, sink);
  229.     
  230.     // Initialize error handling first
  231.     cinfo.err = jpeg_std_error (&jerr);
  232.     jerr.error_exit = (t_jpegemPtr)ODF_JPEG_ErrorManager::ErrorExit;
  233.     if (setjmp (jerr.fExitBuffer)) {
  234.         jpeg_destroy_decompress (&cinfo);
  235.         FW_Failure (FW_xReadableStream);
  236.     }
  237.     
  238.     // Initialize rest of JPEG library
  239.     jpeg_create_decompress (&cinfo);
  240.     src.init_source =         (t_jpegcm1Ptr)ODF_JPEG_SourceManager::InitSource;
  241.     src.fill_input_buffer = (t_jpegcm2Ptr)ODF_JPEG_SourceManager::FillInputBuffer;
  242.     src.skip_input_data =     (t_jpegcm3Ptr)ODF_JPEG_SourceManager::SkipInputData;
  243.     src.resync_to_restart = jpeg_resync_to_restart;
  244.     src.term_source =         (t_jpegcm1Ptr)ODF_JPEG_SourceManager::TermSource;
  245.     src.bytes_in_buffer =     0;
  246.     src.next_input_byte =     nil;
  247.     cinfo.src =             &src;
  248.     
  249.     // Calling C++ code (FW_OSink, FW_CBitmap, etc) can result in exceptions being
  250.     // thrown. Must protect the jpeg_decompress_struct from not being
  251.     // deleted properly. An alternative way to do that would be to subclass
  252.     // it and give it a destructor (and make it an AUTO(destruct) object).
  253.     FW_CBitmap bitmap;
  254.     
  255.     FW_TRY {
  256.     
  257.     // Start reading data
  258.     jpeg_read_header (&cinfo, TRUE);
  259.     jpeg_start_decompress (&cinfo);
  260.     
  261.     // Ok, now we have anything we could possibly need (including the colormap if
  262.     // we asked for color quantization).
  263.     // (1) Create the ODF bitmap object (16-bits deep)
  264.     // (2) Create a work buffer (using the jpeglib's auto-deleting memory manager)
  265.     bitmap = FW_CBitmap (cinfo.output_width, cinfo.output_height, 16);
  266.         //.ChangeBitmap (cinfo.output_width, cinfo.output_height, 16, false);
  267.     if (0) // XXX we don't really need to do this
  268.     {
  269.     // Erase the bitmap; use nested scope to avoid context lifetime/thread 
  270.     // problems. That is, if I didn't use a nested scope then the context (bc) 
  271.     // would stay alive until the end of this function. Since we will be 
  272.     // yielding to other threads during the call to jpeg_read_scanlines below, 
  273.     // other threads could create contexts as well. The ODF graphics layer is 
  274.     // not thread-safe and can't deal with contexts in multiple threads, so we 
  275.     // must force this context to be destroyed ASAP.
  276.     
  277.     FW_CBitmapContext bc (ev, bitmap);
  278.     FW_CMapping mapping (FW_kDevice);
  279.     bc.SetMapping (mapping);
  280.     FW_CPlatformRect bounds (0, 0, cinfo.output_width, cinfo.output_height);
  281.     FW_CRectShape::RenderRect (bc, bounds, FW_kFill, FW_kWhiteEraseInk);
  282.     }
  283.     int bytes = cinfo.output_width * cinfo.output_components;
  284.     JOCTET** buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE, bytes, 1);
  285.     
  286.     // Prepare for decoding the samples
  287.     short width, height, rowBytes, depth;
  288.     bitmap.GetBitmapInfo (width, height, rowBytes, depth); // All I *want* is rowBytes
  289.     FW_PlatformBitmap pb = bitmap.GetPlatformBitmap();
  290.     PixMapHandle pm = ::GetGWorldPixMap (pb);
  291.     Boolean locked = ::LockPixels (pm);
  292.     TempMacLockedPixels unlock (pm);
  293.     Ptr base = ::GetPixBaseAddr (pm);
  294.     
  295.     // Decode each row as it comes in. If we run ahead of the network, the sink object
  296.     // will automatically sleep, so we never need to worry about suspension.
  297.     while (cinfo.output_scanline < cinfo.output_height) {
  298.         jpeg_read_scanlines (&cinfo, buffer, 1);
  299.         ODF_JPEG_DecodeRow (buffer[0], bytes, base, rowBytes);
  300.         base += rowBytes;
  301.     }
  302.     
  303.     jpeg_finish_decompress(&cinfo);
  304.     jpeg_destroy_decompress(&cinfo);
  305.     }
  306.     FW_CATCH_BEGIN
  307.     FW_CATCH_EVERYTHING() {
  308.         jpeg_destroy_decompress(&cinfo);
  309.         FW_THROW_SAME();
  310.     }
  311.     FW_CATCH_END
  312.     
  313.     return bitmap;
  314. }
  315.  
  316.